import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.awt.*;
import java.util.*;

/**
 * Escenario Class
 * @author Flores Hugo Armando Rodriguez
 * @version May 26th 2013
 */
public class Escenario extends World
{
    private ArrayList<Boton> buttons;   //Stores buttons
    private ArrayList<Ninja> ninjas;    //Stores the user ninja, and all the bosses for all the levels
    private Timer timer;    //Represents a timer
    private Records records;    //Store the records
    private GreenfootSound backgroundSound; //Stores the background sound
    private GreenfootSound intro;   //Store the intro sound
    private boolean musicFlag;      //This flag allows the reproduction of the intro song just one time
    private boolean activeOption;   //This flag tells when the menu is availible
    private boolean isPlaying;      //This flag turns true when user is playing
    private boolean activeScore;    //This flag turns true when the first score and backgrounds are created
    private int stage;  //Represents the number of the stage the user is currently playing in
    private int points; //Store the points from thomas

    /**
     * It defines the maximum cells(height and width), and the cell size, then calls the Menu.
     */
    public Escenario()
    {
        super(250, 170, 3);
        buttons=new ArrayList<Boton>();
        for (int i=0; i<4; i++)
            buttons.add(new Boton(i));
        ninjas=new ArrayList<Ninja>();
        records=new Records();
        intro=new GreenfootSound("Running.mp3");
        backgroundSound=new GreenfootSound("Mountain.mp3");
        backgroundSound.setVolume(100);
        intro.setVolume(100);
        activeOption=musicFlag=activeScore=false;
        this.restartGame();
    }
    
    /**
     * This checks various flags for menu or when the user is playing
     */
    public void act()
    {
        if (!musicFlag)
        {
            intro.playLoop();
            musicFlag=true;
        }
        if (Greenfoot.mouseClicked(null) && activeOption && !isPlaying)
        {
            activeOption=false;
            this.deleteAllObjects();
            this.prepareMenu();
        }
        else
            activeOption=true;
        if (isPlaying)
        {
            points=((Thomas)ninjas.get(0)).retPoints();
            this.killBoss();
        }
    }

    /**
     * Puts some messages on the background
     */
    public void messages()
    {
        if (!activeScore)   activeScore=true;
        else    this.removeOldScores();
        String[] strings={"Score:", "Lives:", "Stage:", "Timer:", "Ninja:"};
        int[] values={((Thomas)ninjas.get(0)).retPoints(),((Thomas)ninjas.get(0)).retLives(),stage, ((Thomas)ninjas.get(0)).retLifePercentage()};
        this.addObject(new ScoreBack(), this.getWidth()/2, this.getHeight()/14);
        for (int i=0, x=15, y=7, gapX=82, gapString=39; i<5; i++, x+=gapX)
            if (i<3){
                this.addObject(new Mensaje(strings[i]), x, y);
                this.addObject(new Mensaje(values[i]), x+gapString, y);
            }
            else{
                if (i==3){
                    x=15;
                    this.addObject(timer, x+gapString, 17);
                }
                if (i==4)
                    this.addObject(new Mensaje(values[i-1]), x+gapString, y+10);
                this.addObject(new Mensaje(strings[i]), x, y+10);
        }
    }
    
    /**
     * This prevents overflow on the scores, it deletes them
     */
    public void removeOldScores()
    {
        java.util.List<Actor> messageList=this.getObjects(Mensaje.class);
        java.util.List<Actor> timerList=this.getObjects(Timer.class);
        java.util.List<Actor> scoreBackList=this.getObjects(ScoreBack.class);
        this.removeObjects(messageList);
        this.removeObjects(timerList);
        this.removeObjects(scoreBackList);
    }
    
    /**
     * This method is called from Thomas class, it informs to the world that the user has lost.
     * @param flag is a flag that tells when user thas lost
     */
    public void didYouLost(boolean flag)
    {
        if (flag)
        {
            backgroundSound.stop();
            this.deleteAllObjects();
            this.restartGame();
            musicFlag=false;
        }
    }
    
    /**
     * This deletes all the objects in the world.
     */
    public void deleteAllObjects()
    {
        java.util.List<Actor> list=this.getObjects(null);
        if (list!=null)
            this.removeObjects(list);
    }
    
    /**
     * This prepares the button to visualize the menu.
     */
    public void prepareMenu()
    {
        this.setBackground("ninja.png");
        for (int i=0, x=this.getWidth()/2-45, y=25, gap=10, yButtonSize=25; i<4; i++, y+=yButtonSize+gap+2, x+=gap)
            if (i!=3)
                this.addObject(buttons.get(i), x, y);
            else
            if (UserInfo.isStorageAvailable())
                this.addObject(buttons.get(i), x, y);
    }

    public void menu(int option)
    {
        this.deleteAllObjects(); 
        switch (option)
        {
            case 0: intro.stop();  isPlaying=true; this.stage1();  break;   //Game
            case 1: this.setBackground("help.png");    break;              //Help
            case 2: this.setBackground("credits.png");    break;              //Credits
            case 3: this.setBackground("ninja.png"); records.displayRecords(this);  break;  //records
        }
    }
    
    /**
     * @return the actual records
     */
    public Records getRecords()
    {
        return records;
    }
    
    /**
     * @return the current stage the user is playing in
     */
    public int getStage()
    {
        return stage;
    }
    
    /**
     * @return the timer
     */
    public Timer getTimer()
    {
        return timer;
    }
    
    /**
     * This restart the game, this method is called whenever the user has lost or won in the previous game.
     * Prepares all the objects again.
     */
    public void restartGame()
    {
        this.deleteAllObjects();
        ninjas.clear();
        ninjas.add(0, new Thomas());
        ninjas.add(1, new Gigante());
        ninjas.add(2, new Swordsman());
        ninjas.add(3, new MrZ());
        timer=new Timer(stage=1);
        isPlaying=false;
        this.prepareMenu();
    }
    
    /**
     * Checks what kind of boss is killed
     */
    public void killBoss()
    {
        if (((Jefe)ninjas.get(stage)).getLifePercentage()==0 && isPlaying)
        {
            ((Enemigo)ninjas.get(stage)).setRemoveFlag(true);
            ((Jefe)ninjas.get(stage)).act();
            if (ninjas.get(stage) instanceof Gigante)
            {
                this.nextStage("Stage 2", 2);
                this.stage2();
            }
            else
            if (ninjas.get(stage) instanceof Swordsman)
            {
                this.nextStage("Stage 3", 3);
                this.stage3();
            }
            else
            if (ninjas.get(stage) instanceof MrZ)
            {
                this.nextStage("You Won!!", 1);
                isPlaying=false;
                backgroundSound.stop();
                records.storeScore(points);
                musicFlag=false;
                this.prepareMenu();
            }
        }
    }
    
    /**
     * Displays on the screen what is the next screen the user is going to.
     * @param aString is a string that it is going to be displayed on the screen
     * @param newStage is the next stage the user is going to
     */
    private void nextStage(String aString, int newStage)
    {
        this.addObject(new Mensaje(aString, 40), this.getWidth()/2, this.getHeight()/2);
        Greenfoot.delay(70);
        this.deleteAllObjects();
        stage=newStage;
    }

    /**
     * Prepares the first stage
     */
    private void stage1()
    {
        int[] buildingKind={0,0,3,4,1,2,2,4,4,5,3,2,4,1,1,1,1,6,3,4,0,0,3,6,0,6,6,1,0,7,6,1};//32
        int[][] buildingCoord={{17,70},{48,70},{53,31},{16,31},{90,33},{92,71},{113,71},{103,84}, {122,31},{140,74},{159,31},{142,161},{135,84},
                {16,85},{196,33},{227,33},{233,81},{231,68},{103,133},{140,133},{116,120},{148,120},{21,160},{10,120},{37,120},{10,149},{31,149},
                {72,161},{115,161},{229,110},{167,74},{48,85}};
        int[][] rockCoord={{33,44},{57,54},{66,51},{160,84},{170,85},{208,82},{201,84},{93,115},{248,44},{6,130},{93,166},{249,95},{240,45},
                {187,103},{196,104},{204,101}};
        int[][] antidoteCoord={{203,110},{203,119},{248,168},{215,169},{159,129},{85,86},{155,46},{180,84},{15,125},{50,167},{64,57},{196,44},
                {210,87},{92,124},{7,111}};
        int[][] enemyCoord={{200,67},{180,113},{129,46},{146,58},{227,97},{103,103},{22,103},{100,147},{58,145},{70,85},{192,90},{48,97},{170,140},
                {15,136},{184,57}};
        int[][] lakeCoord={{187,104,0},{192,104,1},{197,104,1},{202,104,1},{207,104,1},{212,104,1},{242,104,2},{217,104,1},{222,104,1},{227,104,1},
                {232,104,1},{237,104,1},{192,109,4},{187,109,3},{187,113,3},{187,118,3},{187,123,3},{187,128,3},{192,114,4},{192,119,4},{192,124,4},
                {192,128,4},{242,109,5},{197,107,5},{197,112,5},{197,117,5},{197,122,5},{197,127,5},{187,143,3},{187,148,3},{187,153,3},{187,158,3},
                {187,163,3},{187,168,3},{192,143,4},{192,148,4},{192,153,4},{192,158,4},{192,163,4},{192,168,4},{197,143,5},{197,148,5},{197,153,5},
                {197,158,5},{197,163,5},{197,168,5}};//46
        backgroundSound.playLoop(); this.setBackground("bkg.png");
        timer=new Timer(2); this.messages();
        for (int i=0; i<46; i++)//for lake
            this.addObject(new Lago(lakeCoord[i][2]), lakeCoord[i][0], lakeCoord[i][1]);
        this.addObject(new Puente(), 192, 135);
        this.addObject(ninjas.get(0), 13, 51);
        this.addObject(ninjas.get(1), 240, 140);
        for (int i=0; i<15; i++) //for enemies
            if (i<9)    this.addObject(new Buck(), enemyCoord[i][0], enemyCoord[i][1]);
            else    this.addObject(new Rick(), enemyCoord[i][0], enemyCoord[i][1]);
        for (int i=0; i<32; i++) //for buildings
            this.addObject(new Edificio(buildingKind[i]), buildingCoord[i][0], buildingCoord[i][1]);
        for (int i=0; i<16; i++) //for rocks
            this.addObject(new Roca(), rockCoord[i][0], rockCoord[i][1]);
        for (int i=0; i<13; i++) //for antidotes
            if (i<8)    this.addObject(new MagicJar(), antidoteCoord[i][0], antidoteCoord[i][1]);
            else    this.addObject(new DoomJar(), antidoteCoord[i][0], antidoteCoord[i][1]);
    }
    
    /**
     * Prepares the second stage
     */
    private void stage2()
    {
        int[] buildingKind={12,12,15,16,11,0,0,1,1,10,14,5,5,6,12,2,1,10,15,9,0,5,11,17,17,17,17,3,4,0,16,12,14,15,15,15};
        int[][] buildingCoord={{14,134},{44,134},{68,134},{88,136},{109,133},{59,162},{91,162},{153,135},{185,135},{211,132},{20,93},{123,165},
                {155,165},{181,165},{235,132},{51,95},{92,95},{118,93},{137,93},{21,36},{92,79},{212,165},{170,93},{88,31},{109,31},{130,31},
                {151,31},{183,31},{220,31},{218,95},{191,96},{162,59},{197,59},{100,59},{138,59},{119,59}};
        int[][] rockCoord={{64,104},{73,104},{73,104},{235,100},{245,98},{242,104},{232,167},{243,166},{5,168},{6,119},{6,77},{12,77},{48,82},
                {68,94},{197,122},{238,35},{243,30},{248,36},{47,35},{55,34},{62,35},{72,33},{87,66},{65,32},{73,33}};//23
        int[][] antidoteCoord={{194,166},{4,149},{41,167},{15,168},{81,125},{95,126},{75,87},{23,79},{36,80},{231,38},{2,49},{2,69},{24,119},
                {247,48},{248,88},{203,91},{162,36},{139,159},{137,141},{249,149},{239,162},{113,74},{69,40},{46,45},{239,95}};//16magicJar,8doomJar
        int[][] enemyCoord={{89,152},{123,152},{173,152},{229,155},{30,114},{57,119},{118,155},{155,103},{224,118},{229,77},{128,77},{181,79},
                {100,45},{196,43},{145,45},{152,152},{80,149},{211,155},{93,115},{174,120},{156,80},{236,60},{68,78}};
        this.setBackground("bkg.png");  timer=new Timer(2); this.messages();
        this.addObject(ninjas.get(0), 13, 157);
        this.addObject(ninjas.get(2), 25, 60);
        for (int i=0; i<23; i++) //for enemies
            if (i<15)    this.addObject(new Julius(), enemyCoord[i][0], enemyCoord[i][1]);
            else    this.addObject(new Buck(), enemyCoord[i][0], enemyCoord[i][1]);
        for (int i=0; i<36; i++) //for buildings
            this.addObject(new Edificio(buildingKind[i]), buildingCoord[i][0], buildingCoord[i][1]);
        for (int i=0; i<23; i++) //for rocks
            this.addObject(new Roca(), rockCoord[i][0], rockCoord[i][1]);
        for (int i=0; i<24; i++) //for antidotes
            if (i<16)    this.addObject(new MagicJar(), antidoteCoord[i][0], antidoteCoord[i][1]);
            else    this.addObject(new DoomJar(), antidoteCoord[i][0], antidoteCoord[i][1]);
    }
    
    /**
     * Prepares the third stage
     */
    private void stage3()
    {
        int[] buildingKind={1,1,1,1,1,1,1,6,6,4,6,14,17,17,17,6,3,8,11,12,14,12,12,12,10,10,3,4,5,5,6,5,5,5,0,0,17,10,12,12,0,0,
                1,4,4,5,17,16,11,0,1,17,2,2,2};
        int[][] buildingCoord={{16,34},{48,34},{80,34},{112,34},{114,34},{176,34},{208,34},{36,61},{57,61},{47,69},{78,61},{109,64},{149,69},
                {169,69},{190,69},{140,59},{221,69},{80,79},{36,81},{40,97},{85,139},{40,107},{40,116},{40,126},{115,139},{134,139},{228,110},
                {166,59},{198,59},{230,59},{11,165},{37,165},{69,165},{101,165},{146,34},{178,111},{190,78},{240,84},{234,94},{158,139},{157,166},
                {189,166},{48,137},{209,117},{117,78},{235,124},{18,68},{7,94},{20,133},{132,107},{131,120},{148,94},{215,150},{215,165},{236,150}};
        int[][] rockCoord={{60,93},{12,117},{200,152},{124,167},{136,169},{249,69},{229,31},{237,31},{246,34},{200,106},{208,101},{175,79},{53,80},
                {12,47},{231,158},{110,122},{102,123},{61,123},{60,114},{4,155}};
        int[][] antidoteCoord={{249,60},{134,69},{229,39},{237,39},{248,43},{248,51},{5,46},{4,56},{26,45},{80,45},{23,119},{5,105},{13,158},{34,145},
                {133,166},{61,107},{69,94},{94,125},{70,124},{231,169},{240,169},{246,168},{245,136},{197,156},{46,42},{227,79},{205,78},
                {216,101},{106,86},{113,114},{105,116},{63,145},{51,145},{149,124},{136,97},{219,126},{167,75}};
        int[][] enemyCoord={{186,46},{90,45},{19,55},{20,82},{7,136},{119,153},{215,86},{230,136},{188,148},{74,51},{37,50},{63,155},{95,158},{221,139},
                {204,89},{160,125},{201,51},{169,51},{36,156},{137,157},{183,130},{155,111},{128,94}};
        this.setBackground("bkg.png");  timer=new Timer(2); this.messages();
        this.addObject(ninjas.get(0), 237, 50);
        this.addObject(ninjas.get(3), 71, 101);
        for (int i=0; i<23; i++) //for enemies
            if (i<9)    this.addObject(new Rick(), enemyCoord[i][0], enemyCoord[i][1]);
            else if (i>=9 && i<16)   this.addObject(new Buck(), enemyCoord[i][0], enemyCoord[i][1]);
            else if (i>=16)  this.addObject(new Julius(), enemyCoord[i][0], enemyCoord[i][1]);
        for (int i=0; i<55; i++) //for buildings
            this.addObject(new Edificio(buildingKind[i]), buildingCoord[i][0], buildingCoord[i][1]);
        for (int i=0; i<20; i++) //for rocks
            this.addObject(new Roca(), rockCoord[i][0], rockCoord[i][1]);
        for (int i=0; i<37; i++) //for antidotes
            if (i<24)    this.addObject(new MagicJar(), antidoteCoord[i][0], antidoteCoord[i][1]);
            else    this.addObject(new DoomJar(), antidoteCoord[i][0], antidoteCoord[i][1]);
    }
}
